桑基图(Sankey Diagram)是一种显示流量数据的可视化图形,在桑基图中,实体(nodes)由矩形或文本表示,实体之间的连接用箭头或弧线表示,箭头或弧线的宽度与流动的重要性或某种数值成比例。
桑基图是一种特定类型的流型图,其中箭头的宽度与流量成比例显示,桑基图将视觉重点放在数据的流动,有助于确定哪个部分对整体流量有主要贡献。
1. 桑基图的历史
桑基图是爱尔兰船长马修亨利菲内亚斯·里尔桑基,于1898年第一次正式使用,船长使用这种图形显示了蒸汽发动机能量效率的变化。
尽管最初的桑基图表仅用于显示一种类型的流(例如蒸汽),但为不同类型的流使用颜色可以为桑基图增加更多的可能性。
最著名的"桑基图"之一是Charles Minard绘制的1812年拿破仑俄国战役地图,这幅图将桑基图叠加在地理地图上,这幅图创建于1869年,因此实际上早于1898年的第一幅正式桑基图。
2. 绘制基础桑基图
桑基图描述了数据之间的流动,绘制桑基图的时候,输入的数据可以有两种不同的数据格式,分别为连接数据框和关联矩阵。
连接数据框包含三列,分别表示连接的起点和终点以及连接的权重。
关联矩阵的行和列分别表示连接,矩阵中的值表示权重,关联矩阵是一个方阵。
连接数据框在数据中逐个列出所有连接,通常数据中有一个source和一个target列,可以添加第三列,为每个连接提供更多信息,例如流的值。
下面的代码构建一个连接数据框并将其表示为Sankey图,如图8.9所示。
2.1 加载包
install.packages("tidyverse") # 安装包
install.packages("networkD3") # 安装包
library(tidyverse) # 加载包
library(networkD3)
2.2 创建数据框
首先创建一个数据集links,这个数据集包含三个变量,分别为source,target和value。
source 表示连接的起点,target表示连接中的终点。
links <- data.frame(
source=c("group_A","group_A", "group_B", "group_C", "group_C", "group_E"),
target=c("group_C","group_D", "group_E", "group_F", "group_G", "group_H"),
value=c(2,3, 2, 3, 1, 3) )
2.3 创建一个关于节点的数据框
创建一个nodes数据集,这个数据集记录了所有连接节点的名称。
nodes <- data.frame(
name=c(as.character(links$source),
as.character(links$target)) %>% unique()
)
nodes %>% head(3)
## name
## 1 group_A
## 2 group_B
## 3 group_C
在数据集links中生成两个新的变量IDsource和IDtarget,这两个变量分别表示对应的source变量和target变量的值在nodes变量中的位置。
# 对于networkD3,必须使用id提供连接,而不是像在links数据集中那样使用实名。所以我们需要重新格式化它。
links$IDsource <- match(links$source, nodes$name)-1
links$IDtarget <- match(links$target, nodes$name)-1
links %>% head(3)
## source target value IDsource IDtarget
## 1 group_A group_C 2 0 2
## 2 group_A group_D 3 0 4
## 3 group_B group_E 2 1 3
举一个例子,在links数据集的输出结果中可以看到,第一行中source变量对应的值为group_A,对应IDsource变量的值为0。
从nodes的输出结果中可以看到,group_A排在第一个,因此IDsource的值则就等于1-1=0。第一行target变量的值为group_C,在nodes中的位置为第三个,因此Idtarget对应的值为3-1=2。
2.4 绘制图形
数据准备好之后,使用sankeyNetwork函数绘制桑基图。代码中设置参数links=links,Nodes=nodes,Nodes和links是两个基本参数。
Souce参数表示数据中的起点,指定此参数为IDsource变量。
Target参数设定为IDtarget变量。
Value参数表示连接的值,设置为value变量。
NodeID参数用于指定所有节点的名称,设置为变量name。
p <- sankeyNetwork(Links = links, Nodes = nodes,
Source = "IDsource", Target = "IDtarget",
Value = "value", NodeID = "name")
p
图 8.9 桑基图
运行代码,即可绘制出桑基图。如果数据集是关联矩阵,则需要先转换数据集,然后重新使用上面的代码绘制图形。
需要注意的是,流量相关的数据都可以使用桑基图进行绘制,例如网络浏览相关的数据,桑基图可以来分析网页中页面跳转的情况,使用桑基图可以很清楚的显示出网络流量在不同页面的变化。
在绘制桑基图的时候,有一些注意事项。
首先桑基图节点的位置非常重要; 另外桑基图的节点不能过多,太多的节点会使得图形过于混乱,难以理解,因此建议删除掉大多数不重要的弱连接。